package store.aixx.jwt.demo.common;

import lombok.RequiredArgsConstructor;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.Arrays;
import java.util.List;

/**
 * 全局 response 返回封装，如果需要自己定义message,则在返回的时候自己构建R对象
 *
 * @author yukai
 * @since 2021年12月11日 21:55
 */
@RequiredArgsConstructor
@RestControllerAdvice
public class GlobalResponseAdvice implements ResponseBodyAdvice<Object> {

    private static final AntPathMatcher pathMatcher = new AntPathMatcher();

    /**
     * 统一包装响应体可忽略的请求 URI 列表
     */
    private static final List<String> ignoredUris = Arrays.asList("/webjars/**", "/doc.html/**", "/swagger-resources/**", "/v2/**", "/error", "/static/*");

    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        Object result = null;
        if (ignoredMediaType(mediaType) || ignoreRequest(request) || body instanceof R){
            result =  body;

        }else{
            result = R.Success(body);
        }
        return result;
    }

    /**
     * 判断可忽略的 Media Type
     */
    private boolean ignoredMediaType(MediaType mediaType) {
        // 文件下载、图片请求，不需要统一包装响应体
        return Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.IMAGE_JPEG).contains(mediaType);
    }

    /**
     * 判断可忽略的请求 URI
     * @param request
     * @return
     */
    private boolean ignoreRequest(ServerHttpRequest request){
        String path = request.getURI().getPath();
        return ignoredUris.stream().anyMatch(uri -> pathMatcher.match(uri, path));
    }
}
